
//#define _test_
#include <stdio.h>
#include "Cursor.h"

#define CURSOR_POSITION_X write_cursor[0]
#define CURSOR_POSITION_Y write_cursor[1]
#define WHICH_LINE write_cursor[2]
#define LINE_INDEX write_cursor[3]

#define LINE_MAX (getCol() - WRITINGX - RIGHTSPACE)
#define LINEX 0
#define LINEY 1


#define SPACE L" "

static int write_cursor[4];
static ContentList * content_article = NULL;
static ContentList * file_names = NULL;

static int checked_dict_number = 0;
static int hidden_dict_number = 0;

//announce for private methods
int _private_print(wchar_t);
int _private_fillLine(struct String *, int, int);
void _private_fillSpace(int);
int* _private_get_xy_inline(struct String*, int);


int* _private_get_xy_inline(struct String * sentence, int index){
	int i;
	int x = 0;
	int y = 0;
	int startIndex = 0;
	int* res = (int*) malloc(sizeof(int) * 2);
	if(index > lenOfStr(sentence) || index <= 0){
		index = lenOfStr(sentence);
	}
	while(startIndex < index){
		for(i = 0, x = 0; i < LINE_MAX; i++, startIndex++, x++){
			if(0xffffff00 & sentence -> str[startIndex]){
				i++;
			}
		}
		y++;
	}
	res[LINEX] = x;
	res[LINEY] = y;
	return res;
}


int GET_CURSOR_POSITION_X(void){
	return CURSOR_POSITION_X;
}

int GET_CURSOR_POSITION_Y(void){
	return CURSOR_POSITION_Y;
}

ContentList* GET_FILENAMES(void){
	return file_names;
}

ContentList* GET_CONTENT_ARTICLE(void){
	return content_article;
}

void writeLineNumber(int lineCount, int number){
	moveTo(LINECOUNTX, lineCount);
	printf("%3d", number);
}

void printSth(wchar_t word){
	int* lineXY;
	strInsert(LINE_INDEX, word, getContent(WHICH_LINE, content_article));
	CURSOR_POSITION_X ++;
	LINE_INDEX ++;
	lineXY = _private_get_xy_inline(getContent(WHICH_LINE, content_article), LINE_INDEX);
	if(lineXY[LINEX] < CURSOR_POSITION_X)
		lineExtend();
	
	printf("%lc", word);
	free(lineXY);
}

int _private_print(wchar_t word){
	printf("%lc", word);
	if(0xffffff00 & word){
		return 2;
	}else{
		return 1;
	}
}


int _private_fillLine(struct String * str, int strIndex, int lineIndex){
	int i;
	int strLen = lenOfStr(str);
	int lineSpace;
	const int lineMax = getCol() - WRITINGX - RIGHTSPACE;
	moveTo(WRITINGX, lineIndex);
	for(i = 0, lineSpace = 0; lineSpace < lineMax && i + strIndex < strLen; i++){
		lineSpace += _private_print(str -> str[i + strIndex]);
	}
	return i;
}

void _private_fillSpace(int lineIndex){
	int i;
	const int lineMax = getCol() - WRITINGX - RIGHTSPACE;
	for(i = 0; i < lineMax; i++)
		printf(" ");
}

void fillWritingBoardWithArticle(int startY, int startLine){
	struct String * lineSentence;
	int y;
	int len;
	int articleLineCount;
	int index = 0;

	articleLineCount = lenOfContent(content_article);

	lineSentence = getContent(startLine++, content_article);
	len = lenOfStr(lineSentence);
	for(y = startY; y <= getRow(); y++){
		if(startLine - 1 >= articleLineCount){
			_private_fillSpace(y);
			writeLineNumber(y, startLine - 1);
			startLine ++;
		}else if(index < len){
			index += _private_fillLine(lineSentence, index, y);
			writeLineNumber(y, startLine - 1);
		}else{
			index = 0;
			lineSentence = getContent(startLine++, content_article);
			len = lenOfStr(lineSentence);
			y--;
		}
	}
}

//你XX
//叫你关机你不关机
//你XX

void lineExtend(void){
	int i;
	//如果页数不够，翻页
	if(CURSOR_POSITION_Y >= getRow()){
		articleScroll(1);
	}
	//填充后面的文字
	for(i = CURSOR_POSITION_Y + 1; i <= getRow(); i++){
		_private_fillSpace(i);
	}
	writeLineNumber(CURSOR_POSITION_Y + 1, WHICH_LINE);
	fillWritingBoardWithArticle(CURSOR_POSITION_Y + 2, WHICH_LINE + 1);
	CURSOR_POSITION_X = 0;
	CURSOR_POSITION_Y ++;
}

void newLine(void){
	if(CURSOR_POSITION_Y >= getRow()){
		articleScroll(1);
	}
	CURSOR_POSITION_Y ++;
	CURSOR_POSITION_X = 0;
	LINE_INDEX = 0;
	WHICH_LINE ++;
	struct String* newLineSentence = initString();
	insertContent(newLineSentence, WHICH_LINE, content_article);
	_private_fillSpace(CURSOR_POSITION_Y);
	writeLineNumber(WHICH_LINE, CURSOR_POSITION_Y);
	fillWritingBoardWithArticle(CURSOR_POSITION_Y + 1, WHICH_LINE + 1);
	moveTo(CURSOR_POSITION_X + WRITINGX, CURSOR_POSITION_Y);
}

void _allFileNames(){
	wchar_t * filename;

	if(readToContent(CONF_FILE, file_names) != 0)
		return;
	while( wcscmp(filename = getFiles(), ENDOFFILES) != 0){
		if(wcscmp(filename, CONF_FILE) != 0){
			pushContentByCharArray(filename, file_names, wcslen(filename) * 2);
		}else{
			free(filename);
		}
	}	
}

void drawScreen(void){
	int i;
	struct String * filename;
	sizeRefresh();
	clearScreen();
	for(i = 0; i < getRow(); i++){
		printf("|%-20ls\t", SPACE);
		printf("|%3d|", i + 1);	
		if(i + 1 != getRow())
			printf("\n");
	}
}

void articleScroll(int num){
	int startLine = WHICH_LINE;
	const int lineMax = getCol() - WRITINGX - RIGHTSPACE;
	int upLineCount = CURSOR_POSITION_Y;
	int i;
	int hiddenLineCount = 0;
	
	startLine -= upLineCount;
	for(i = WHICH_LINE; i > startLine; i--){
		startLine += spaceOfStr(getContent(i, content_article), 0) / lineMax;
	}
	fillWritingBoardWithArticle(1, startLine + num);
	if(num > 0){
		for(i = startLine; i < startLine + num; i++){
			hiddenLineCount += spaceOfStr(getContent(i, content_article), 0) / lineMax + 1;
		}
		CURSOR_POSITION_Y -= hiddenLineCount;
	}else if(num < 0){
		for(i = startLine; i > startLine - num; i--){
			hiddenLineCount += spaceOfStr(getContent(i, content_article), 0) / lineMax + 1;
		}
		CURSOR_POSITION_Y += hiddenLineCount;
	}
	moveTo(CURSOR_POSITION_X + WRITINGX, CURSOR_POSITION_Y);
}

void initWriting(){
	CURSOR_POSITION_X = 0;
	CURSOR_POSITION_Y = 0;
	WHICH_LINE = 0;
	LINE_INDEX = 0;
	
	if(content_article != NULL){
		deleteContent(content_article);
		content_article = initContent();
	}
	if(file_names == NULL){
		file_names = initContent();
		_allFileNames();
	}
	if(checked_dict_number < lenOfContent(file_names)){
		//readToContent(getContent(checked_dict_number, file_names) -> str, content_article);
		//fillWritingBoardWithArticle(0, 0);
	}
}

void cursorUp(){
	int lastLen, thisLineIndex, indexSpace, lastTotleSpace, lastIndexSapce;
	struct String * lastStr;
	struct String * thisStr;
	int* thisLineXY;
	int* lastLineXY;
	int* lastLineEndXY;
	if(WHICH_LINE > 0){
		thisStr = getContent(WHICH_LINE, content_article);
		lastStr = getContent(WHICH_LINE - 1, content_article);
		if(CURSOR_POSITION_Y <= 1){
			articleScroll(-1);
		}
		thisLineIndex = LINE_INDEX;
		lastLen = lenOfStr(lastStr);
		if(lastLen <= thisLineIndex){
			LINE_INDEX = lastLen - 1;
		}
		//_private_get_xy_inline(struct String * sentence, int index)
		thisLineXY = _private_get_xy_inline(thisStr, thisLineIndex);
		lastLineXY = _private_get_xy_inline(lastStr, LINE_INDEX);
		lastLineEndXY = _private_get_xy_inline(lastStr, 0);
		CURSOR_POSITION_Y -= lastLineEndXY[LINEY] + thisLineXY[LINEY] - lastLineXY[LINEY];
		CURSOR_POSITION_X = lastLineXY[LINEY];
		WHICH_LINE --;
		moveTo(CURSOR_POSITION_X + WRITINGX, CURSOR_POSITION_Y);

		free(thisLineXY);
		free(lastLineXY);
		free(lastLineEndXY);
	}
}

void cursorDown(){
	int thisLen, nextLen, thisLineIndex;
	const int lineMax = getCol() - WRITINGX - RIGHTSPACE;
	struct String * thisStr;
	struct String * nextStr;
	int* thisLineXY;
	int* nextLineXY;
	int* thisLineEndXY;
	if(WHICH_LINE < lenOfContent(content_article) - 1){
		if(CURSOR_POSITION_Y >= getRow() - 1){
			articleScroll(1);
		}
		thisStr = getContent(WHICH_LINE, content_article);
		nextStr = getContent(WHICH_LINE + 1, content_article);
		thisLen = lenOfStr(thisStr);
		nextLen = lenOfStr(nextStr);
		thisLineIndex = LINE_INDEX;
		if(LINE_INDEX >= nextLen){
			LINE_INDEX = nextLen - 1;
		}
		thisLineXY = _private_get_xy_inline(thisStr, thisLineIndex);
		nextLineXY = _private_get_xy_inline(nextStr, LINE_INDEX);
		thisLineEndXY = _private_get_xy_inline(thisStr, 0);
		CURSOR_POSITION_Y += thisLineEndXY[LINEY] - thisLineXY[LINEY] + nextLineXY[LINEY];
		CURSOR_POSITION_X = nextLineXY[LINEX];
		WHICH_LINE ++;
		moveTo(WRITINGX + CURSOR_POSITION_X, CURSOR_POSITION_Y);

		free(thisLineXY);
		free(nextLineXY);
		free(thisLineEndXY);

	}
}

void cursorLeft(){
	int *xy;
	struct String * sentence;
	if(LINE_INDEX > 0){
		LINE_INDEX --;
		if(CURSOR_POSITION_X > 0){
			CURSOR_POSITION_X --;
		}else if(LINE_INDEX >= 0){
			xy = _private_get_xy_inline(getContent(WHICH_LINE, content_article), LINE_INDEX);
			CURSOR_POSITION_Y -= 1;
			CURSOR_POSITION_X = xy[LINEX];
		}else{
			if(CURSOR_POSITION_Y <= 1){
				articleScroll(-1);
			}
			WHICH_LINE --;
			sentence = getContent(WHICH_LINE, content_article);
			LINE_INDEX = lenOfStr(sentence) - 1;
			xy = _private_get_xy_inline(sentence, LINE_INDEX);
			CURSOR_POSITION_X = xy[LINEX];
			CURSOR_POSITION_Y --;
		}
		moveTo(WRITINGX + CURSOR_POSITION_X, CURSOR_POSITION_Y);
		free(xy);
	}
}

void cursorRight(){
	struct String * sentence = getContent(WHICH_LINE, content_article);
	int length = lenOfStr(sentence);
	int* xy = _private_get_xy_inline(sentence, LINE_INDEX);
	if(LINE_INDEX < length - 1){
		LINE_INDEX ++;
		if(xy[LINEX] >= LINE_MAX){
			if(CURSOR_POSITION_Y >= getRow() - 1){
				articleScroll(1);
			}
			CURSOR_POSITION_Y ++;
			CURSOR_POSITION_X = 0;
		}else{
			CURSOR_POSITION_X ++;
		}
	}else if(WHICH_LINE < lenOfContent(content_article) - 1){
		if(CURSOR_POSITION_Y >= getRow() - 1){
			articleScroll(1);
		}
		WHICH_LINE ++;
		LINE_INDEX = 0;
		CURSOR_POSITION_X = 0;
		CURSOR_POSITION_Y ++;
	}
	moveTo(WRITINGX + CURSOR_POSITION_X, CURSOR_POSITION_Y);
	free(xy);
}


void cursorBack(){
	struct String* thisStr = NULL;
	struct String* lastStr = NULL;
	int* nowXY;
	int* originXY;
	int* indexXY;
	thisStr = getContent(WHICH_LINE, content_article);
	if(WHICH_LINE > 0){
		lastStr = getContent(WHICH_LINE - 1, content_article);
	}
	
	originXY = _private_get_xy_inline(thisStr, 0);
	if(LINE_INDEX > 0){
		strDelete(thisStr, LINE_INDEX);
		LINE_INDEX --;
	}else if(WHICH_LINE > 0){
		LINE_INDEX = lenOfStr(lastStr) - 1;
		if(lenOfStr(thisStr) != 0){
			strAppend(lastStr, thisStr);
		}
		deleteValue(WHICH_LINE, content_article);
		WHICH_LINE --;
	}
	thisStr = getContent(WHICH_LINE, content_article);
	nowXY = _private_get_xy_inline(thisStr, 0);
	indexXY = _private_get_xy_inline(thisStr, LINE_INDEX);
	fillWritingBoardWithArticle(CURSOR_POSITION_Y - originXY[LINEY], WHICH_LINE);
	CURSOR_POSITION_X = indexXY[LINEX];
	CURSOR_POSITION_Y += -originXY[LINEY] + indexXY[LINEY];

	moveTo(WRITINGX + CURSOR_POSITION_X, CURSOR_POSITION_Y);
	free(nowXY);
	free(originXY);
	free(indexXY);
}



//--------------后面的方法用于写目录------------------------
void _use_checked(){
	SET_COLOR(FRONT_CHECKED);
	SET_COLOR(BACKGROUND_CHECKED);
}
void _use_normal(){
	SET_COLOR(FRONT_NORMEL);
	SET_COLOR(BACKGROUND_NORMEL);
}
void _use_alert(){
	SET_COLOR(FRONT_ALERT);
	SET_COLOR(BACKGROUND_ALERT);
}
void _use_input(){
	SET_COLOR(FRONT_ALERT);
	SET_COLOR(BACKGROUND_ALERT);
}

int GET_CHECKED_DICT_NUM(void){
	return checked_dict_number;
}
void writeDicts(){
	int i;
	struct String * str = NULL;
	for(i = 0; i < getRow(); i++){
		moveTo(TAGX, i + 1);
		str = getContent(i + hidden_dict_number, file_names);
		if(i == checked_dict_number - hidden_dict_number){
			_use_checked();
			printf("%-21ls", str == NULL ? L" " : str -> str);
			_use_normal();
		}else{
			printf("%-21ls", str == NULL ? L" " : str -> str);
		}
	}
	str = getContent(checked_dict_number, file_names);
	moveTo(TAGX + lenOfStr(str) + 1, checked_dict_number - hidden_dict_number + 1);
}



void dictScroll(int i){
	int this_line = checked_dict_number - hidden_dict_number;
	if(i > 0 && this_line + i > getRow()){
		if(checked_dict_number + i >= lenOfContent(&file_names)){
			return;
		}else{
			hidden_dict_number += this_line + i - getRow();
			checked_dict_number += i;
			writeDicts();
		}
	}else if(i < 0 && this_line + i < 0){
		if(hidden_dict_number + this_line + i < 0){
			return;
		}else{
			hidden_dict_number += this_line + i;
			checked_dict_number += i;
			writeDicts();
		}
	}else{
		moveTo(TAGX, checked_dict_number - hidden_dict_number + 1);
		_use_normal();
		printf("%-20ls", getContent(checked_dict_number, &file_names) -> str);
		checked_dict_number += i;
		moveTo(TAGX, checked_dict_number - hidden_dict_number + 1);
		_use_checked();
		printf("%-20ls", getContent(checked_dict_number, &file_names) -> str);
		_use_normal();
	}
}


void dictBackSpace(){
	struct String * nowTitle = getContent(checked_dict_number, file_names);
	strDelete(lenOfStr(nowTitle) - 1, nowTitle);
	moveTo(TAGX + spaceOfStr(nowTitle, 0), checked_dict_number - hidden_dict_number + 1);
	_use_checked();
	printf("  ");
	moveTo(TAGX + spaceOfStr(nowTitle, 0), checked_dict_number - hidden_dict_number + 1);
	_use_normal();
}

void dictAppend(wchar_t wc){
	struct String * nowTitle = getContent(checked_dict_number, file_names);
	int space = spaceOfStr(nowTitle, 0);
	int len = lenOfStr(nowTitle);
	if(space > 20){
		return;
	}
	strInsert(len, wc, nowTitle);
	_use_checked();
	printf("%lc", wc);
	_use_normal();
}
